/**
 * @Project POL3Cay
 * @Author Tran Manh Hung
 * @Email: hungtmit@gmail.com | tmh@xwebgate.com
 * @Copyright © 2011 TMH. All rights reserved
 * @Createdate Feb 23, 2011
 * @Createtime 11:44:50 AM
 */

package com.xwg.cards
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.filters.BitmapFilterQuality;
	import flash.filters.BlurFilter;
	import flash.filters.DropShadowFilter;
	import flash.filters.GlowFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Transform;

	public class BaseHandRenderer extends Sprite
	{
		public static const CARD_SIZE_BIG:uint = 1;

		public static const CARD_SIZE_MEDIUM:uint = 2;

		public static const CARD_SIZE_SMALL:uint = 4;

		//private var _cardsSetVSO:Vector.<CardRendererVDO>;

		private var _cardSize:uint;

		protected var _openAngle:int = 0;

		protected var _radius:int = 0;

		private var _baseHand:BaseHand;

		private var _cardsSetRenderer:Vector.<CardRenderer>;

		private var _gap:int = 0;

		private var _isHorizontal:Boolean = true;

		private var _zoneAnchor:Point = new Point();

		private var cardThrowZOrder:int = 0;

		private var zoneHeight:Number = 30;

		//private var zoneHeight:Number = 0;

		private var zoneWidth:Number = 40;

		//private var zoneWidth:Number = 0;

		private var glowFilter:GlowFilter;

		private var globalTableCenter:Point;

		public function BaseHandRenderer(baseHand:BaseHand = null, cardSize:uint = CARD_SIZE_MEDIUM)
		{
			super();

			_baseHand = baseHand;

			_cardsSetRenderer = new Vector.<CardRenderer>();

			globalTableCenter = new Point();

			glowFilter = new GlowFilter(0, .36, 4, 4);

			//_cardsSetVSO = new Vector.<CardRendererVDO>();

			for (var i:int = 0; i < Deck.SIZE; i++)
			{
				_cardsSetRenderer[i] = new CardRenderer(_baseHand.cardsSet[i]);
				// _cardsSetRenderer[i].filters = [new DropShadowFilter(4, 135, 0, .6)];
				_cardsSetRenderer[i].filters = [glowFilter];
				addChild(_cardsSetRenderer[i]);

					//_cardsSetVSO[i] = new CardRendererVDO();
			}

			this.cardSize = cardSize;
		}

		public function sort():void
		{
			_cardsSetRenderer.sort(sortByValue);

			var cardIndex:int = 0;

			/* sort by base hand
			for (var i:int = 0; i < Deck.SIZE; i++)
			{
				if (_baseHand.cardsSet[i].onHand)
				{
					_cardsSetRenderer[cardIndex].card = _baseHand.cardsSet[i];

					setChildIndex(_cardsSetRenderer[i], cardIndex);

					_cardsSetRenderer[cardIndex].cardValueChangeHandler(null);

					cardIndex++;
				}
			}
			*/

			for (var i:int = 0; i < Deck.SIZE; i++)
			{
				if (_cardsSetRenderer[i].card.onHand)
				{
					setChildIndex(_cardsSetRenderer[i], i);
				}
				else
				{
					setChildIndex(_cardsSetRenderer[i], 0);
				}
			}
		}

		private function sortByValue(a:CardRenderer, b:CardRenderer):int
		{
			var ret:int = 0;

			if (a.card.rank < b.card.rank)
			{
				ret = -1;
			}
			else if (a.card.rank > b.card.rank)
			{
				ret = 1;
			}
			else // a==b
			{
				if (a.card.suitRank < b.card.suitRank)
				{
					ret = -1;
				}
				else if (a.card.suitRank > b.card.suitRank)
				{
					ret = 1;
				}
				else // never reach here
				{
					ret = 0;
				}
			}

			return ret;
		}

		/**
		 * apply visual change to card set ON HAND<br />
		 * @param allCard
		 */
		public function render(allCard:Boolean = false):void
		{
			for (var i:uint = 0; i < Deck.SIZE; i++)
			{
				if (allCard)
				{
					/*
					_cardsSetRenderer[i].x = _cardsSetVSO[i].x;
					_cardsSetRenderer[i].y = _cardsSetVSO[i].y;
					_cardsSetRenderer[i].rotationZ = _cardsSetVSO[i].rotationZ;
					//*/

					_cardsSetRenderer[i].x = _cardsSetRenderer[i].cardVSO.x;
					_cardsSetRenderer[i].y = _cardsSetRenderer[i].cardVSO.y;
					_cardsSetRenderer[i].rotationZ = _cardsSetRenderer[i].cardVSO.rotationZ;
				}
				else
				{
					//if (_baseHand.cardsSet[i].onHand)
					if (_cardsSetRenderer[i].card.onHand)
					{
						/*
						_cardsSetRenderer[i].x = _cardsSetVSO[i].x;
						_cardsSetRenderer[i].y = _cardsSetVSO[i].y;
						_cardsSetRenderer[i].rotationZ = _cardsSetVSO[i].rotationZ;
						//*/

						_cardsSetRenderer[i].x = _cardsSetRenderer[i].cardVSO.x;
						_cardsSetRenderer[i].y = _cardsSetRenderer[i].cardVSO.y;
						_cardsSetRenderer[i].rotationZ = _cardsSetRenderer[i].cardVSO.rotationZ;
					}
				}
			}
		}

		public function computeThrowLine(gap:int = 23, isHorizontal:Boolean = true):void
		{
			var position:int = 0; // cards threw

			/**
			 * how many cards threw
			 */
			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				//if (!_baseHand.cardsSet[i].onHand && _baseHand.cardsSet[i].selected) // not on hand and selected
				if (!_cardsSetRenderer[i].card.onHand && _cardsSetRenderer[i].card.selected) // not on hand and selected
				{
					_cardsSetRenderer[i].rotationZ = 0; // if not reset rotationZ to 0 it will skew card

					//_cardsSetRenderer[i].width = 45;
					//_cardsSetRenderer[i].height = 60;
					_cardsSetRenderer[i].scaleX = .375;
					_cardsSetRenderer[i].scaleY = .375;

					position++;
				}
			}

			var cPoint:Point = new Point();

			/**
			 * offsetX to align center threw cards set
			 */
			//var offsetX:int = 0;

			//** center card throw position
			var offsetX:int = (13 - position) * gap / 2;
			cPoint.x = Math.round(_zoneAnchor.x + offsetX + zoneWidth * Math.random());

			// */

			/** random card throw position
			var offsetX:int = (13 - position) * 15;
			cPoint.x = Math.round(_zoneAnchor.x + (offsetX + zoneWidth) * Math.random());

			// */

			cPoint.y = Math.round(_zoneAnchor.y + zoneHeight * Math.random());

			position = 0;

			for (i = 0; i < _cardsSetRenderer.length; i++)
			{
				//if (!_baseHand.cardsSet[i].onHand && _baseHand.cardsSet[i].selected) // not on hand and selected
				if (!_cardsSetRenderer[i].card.onHand && _cardsSetRenderer[i].card.selected) // not on hand and selected
				{
					if (isHorizontal)
					{
						/*
						_cardsSetVSO[i].x = cPoint.x + position * gap;
						_cardsSetVSO[i].y = cPoint.y;
						_cardsSetVSO[i].rotationZ = -5 + Math.random() * 10; // rotation a bit for good look anh feel
						//*/

						_cardsSetRenderer[i].cardVSO.x = cPoint.x + position * gap;
						_cardsSetRenderer[i].cardVSO.y = cPoint.y;
						_cardsSetRenderer[i].cardVSO.rotationZ = -5 + Math.random() * 10; // rotation a bit for good look anh feel

						/**
						 * last throw card alway on top of previous threw cards
						 */
						setChildIndex(_cardsSetRenderer[i], cardThrowZOrder);
					}

					position++;
					cardThrowZOrder++;

					_baseHand.cardsSet[i].selected = false;
				}
			}
		}

		/**
		 * THROW ALL SELECTED CARD ON HAND<br />
		 * ~ set on hand of selected cards = false
		 */
		public function throwCard(visible:Boolean = true):void
		{
			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (_cardsSetRenderer[i].card.onHand && _cardsSetRenderer[i].card.selected)
				{
					_cardsSetRenderer[i].card.onHand = false;

					_cardsSetRenderer[i].card.selected = visible; // !!!

					_cardsSetRenderer[i].card.visible = visible;

					_baseHand.numCards--;
				}
			}
		}

		public function computeRenderCurve(openAngle:int = 150, radius:int = 180):void
		{
			var position:int = 1;

			//var stepAngle:Number = openAngle / (_baseHand.numCards + 1);
			var stepAngle:Number = openAngle / 14; // 14 = 13+1
			// var offsetAngle:Number = (openAngle - 180) / 2; // to center hand card
			var offsetAngle:Number = (openAngle - 180 + stepAngle * (13 - _baseHand.numCards)) / 2; // to center hand card

			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (_cardsSetRenderer[i].card.onHand)
				{
					/*
					_cardsSetVSO[i].y = radius * Math.sin((offsetAngle + position * stepAngle - openAngle) / 180 * Math.PI);
					_cardsSetVSO[i].x = radius * Math.cos((offsetAngle + position * stepAngle - openAngle) / 180 * Math.PI);
					_cardsSetVSO[i].rotationZ = (90 + offsetAngle + position * stepAngle - openAngle) % 360;
					//*/

					_cardsSetRenderer[i].cardVSO.y = radius * Math.sin((offsetAngle + position * stepAngle - openAngle) / 180 * Math.PI);
					_cardsSetRenderer[i].cardVSO.x = radius * Math.cos((offsetAngle + position * stepAngle - openAngle) / 180 * Math.PI);
					_cardsSetRenderer[i].cardVSO.rotationZ = (90 + offsetAngle + position * stepAngle - openAngle) % 360;

					position++;
				}
			}

			_radius = radius;
			_openAngle = openAngle;
		}

		public function computeRenderLine(gap:int = 30, isHorizontal:Boolean = true):void
		{
			var position:int = 0;

			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (_cardsSetRenderer[i].card.onHand)
				{
					if (isHorizontal)
					{
						/*
						_cardsSetVSO[i].x = position * gap;
						_cardsSetVSO[i].y = 0;
						//*/

						_cardsSetRenderer[i].cardVSO.x = position * gap;
						_cardsSetRenderer[i].cardVSO.y = 0;
					}

					position++;
				}
			}

			_gap = gap;
			_isHorizontal = isHorizontal;
		}

		public function computeRenderToTableCenter(globalTableCenter_:Point):void
		{
			// var localTableCenter:Point = globalToLocal(new Point(globalTableCenter.x, globalTableCenter.y));
			globalTableCenter = globalToLocal(new Point(globalTableCenter_.x, globalTableCenter_.y));

			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (_cardsSetRenderer[i].card.onHand)
				{
					/*
					_cardsSetVSO[i].x = localTableCenter.x;
					_cardsSetVSO[i].y = localTableCenter.y;
					_cardsSetVSO[i].rotationZ = 0;
					//*/

					_cardsSetRenderer[i].cardVSO.x = globalTableCenter.x;
					_cardsSetRenderer[i].cardVSO.y = globalTableCenter.y;
					_cardsSetRenderer[i].cardVSO.rotationZ = 0;
				}
			}
		}

		public function computeHideThrewCard():void
		{
			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (!_cardsSetRenderer[i].card.onHand && _cardsSetRenderer[i].card.revealed)
				{
					_cardsSetRenderer[i].card.revealed = false;
					_cardsSetRenderer[i].card.selected = false;

					// _cardsSetRenderer[i].cardVSO.x = globalTableCenter.x;
					// _cardsSetRenderer[i].cardVSO.y -= 200;

					_cardsSetRenderer[i].cardVSO.x = globalTableCenter.x + 400;
					_cardsSetRenderer[i].cardVSO.y = globalTableCenter.y;
					_cardsSetRenderer[i].cardVSO.rotationZ = 0;
				}
			}
		}

		public function hideThrewCard():void
		{
			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (!_cardsSetRenderer[i].card.onHand)
				{
					_cardsSetRenderer[i].card.revealed = false;
					_cardsSetRenderer[i].card.selected = false;
					_cardsSetRenderer[i].card.visible = false;
				}
			}
		}

		public function resetData():void
		{
			_baseHand.resetData();

			for (var i:uint = 0; i < Deck.SIZE; i++)
			{
				_cardsSetRenderer[i].resetData();
			}

			cardSize = _cardSize; // reset card size

			_radius = 0;
			_openAngle = 0;
			cardThrowZOrder = 0;

			visible = false;
			alpha = 1;
		}

		public function computeMoveAllThrewCard(offX:Number, offY:Number):void
		{
			for (var i:uint = 0; i < _cardsSetRenderer.length; i++)
			{
				if (!_cardsSetRenderer[i].card.onHand) // not on hand and visible
				{
					/*
					_cardsSetVSO[i].x += offX;
					_cardsSetVSO[i].y += offY;
					//*/

					_cardsSetRenderer[i].cardVSO.x += offX;
					_cardsSetRenderer[i].cardVSO.y += offY;
				}
			}
		}

		/**
		 * set cards will be throw by a string
		 */
		public function setCardsThrowString(cardsString:String, revealCard:Boolean = true, selectCard:Boolean = true):void
		{
			var cardStrings:Array = cardsString.split(' ');

			var cardIndex:uint = 0;

			var card:Card;

			for (var i:int = 0; i < Deck.SIZE; i++)
			{
				if (_cardsSetRenderer[i].card.onHand)
				{
					card = _stringToCard(cardStrings[cardIndex]);

					_cardsSetRenderer[i].card.setCard(card.value, card.suit);
					_cardsSetRenderer[i].card.revealed = revealCard;
					_cardsSetRenderer[i].card.selected = selectCard;

					cardIndex++;

					if (cardIndex == cardStrings.length)
					{
						break;
					}
				}
			}
		}

		public function receiveCardsString(cardsString:String, revealCard:Boolean = false, interactable:Boolean = false):void
		{
			var cardStrings:Array = cardsString.split(' ');

			for (var i:int = 0; i < cardStrings.length; i++)
			{
				if (i == 0) // reset rank at new turn
				{
					_baseHand.resetData();
				}

				_baseHand.receiveCard(_stringToCard(cardStrings[i]), i, revealCard, interactable); // ERR
			}
		}

		private function _stringToCard(cardString:String):Card
		{
			var value:String;

			var suitChar:String

			if (cardString.length == 3) // 10
			{
				value = "10";

				suitChar = cardString.charAt(2);
			}
			else // length == 2
			{
				value = cardString.charAt(0);

				suitChar = cardString.charAt(1);
			}

			var card:Card = new Card();
			card.value = value;
			card.suit = suitChar;

			return card;
		}

		public function toStringExt(allCard:Boolean = false):String
		{
			var ret:String = "";

			for (var i:uint = 0; i < Deck.SIZE; i++)
			{
				if (allCard)
				{
					ret += _cardsSetRenderer[i].card.toStringExt() + " ";
				}
				else
				{
					if (_cardsSetRenderer[i].card.onHand)
					{
						ret += _cardsSetRenderer[i].card.toStringExt() + " ";
					}
				}
			}

			return ret;
		}

		public function get radius():int
		{
			return _radius;
		}

		public function set radius(value:int):void
		{
			if (_radius != value)
			{
				computeRenderCurve(_openAngle, _radius);

				_radius = value;
			}
		}

		public function get openAngle():int
		{
			return _openAngle;
		}

		public function set openAngle(value:int):void
		{
			if (_openAngle != value)
			{
				computeRenderCurve(_openAngle, _radius);

				_openAngle = value;
			}
		}

		public function get cardsSetRender():Vector.<CardRenderer>
		{
			return _cardsSetRenderer;
		}

		public function get zoneAnchor():Point
		{
			return _zoneAnchor;
		}

		public function set zoneAnchor(value:Point):void
		{
			var localAnchor:Point = globalToLocal(new Point(value.x, value.y));

			_zoneAnchor = localAnchor;

			// _zoneAnchor = value
		}

		public function get baseHand():BaseHand
		{
			return _baseHand;
		}

		public function set baseHand(value:BaseHand):void
		{
			_baseHand = value;
		}

		/*
		public function get cardsSetVSO():Vector.<CardRendererVDO>
		{
			return _cardsSetVSO;
		}

		public function set cardsSetVSO(value:Vector.<CardRendererVDO>):void
		{
			_cardsSetVSO = value;
		}
		//*/

		public function get cardSize():uint
		{
			return _cardSize;
		}

		/**
		 * @param value uint - BaseHandRenderer.CARD_SIZE_*
		 */
		public function set cardSize(value:uint):void
		{
			_cardSize = value;

			for (var i:int = 0; i < Deck.SIZE; i++)
			{
				switch (_cardSize)
				{
					case CARD_SIZE_BIG:
						// _cardsSetRenderer[i].width = 120;
						// _cardsSetRenderer[i].height = 160;
						_cardsSetRenderer[i].scaleX = 1;
						_cardsSetRenderer[i].scaleY = 1;

						glowFilter.blurX = 8;
						glowFilter.blurY = 8;
						glowFilter.alpha = .6;
						break;
					case CARD_SIZE_MEDIUM:
						// _cardsSetRenderer[i].width = 60;
						// _cardsSetRenderer[i].height = 80;
						_cardsSetRenderer[i].scaleX = .5;
						_cardsSetRenderer[i].scaleY = .5;

						glowFilter.blurX = 4;
						glowFilter.blurY = 4;
						glowFilter.alpha = .6;
						break;
					case CARD_SIZE_SMALL:
						// _cardsSetRenderer[i].width = 30;
						// _cardsSetRenderer[i].height = 40;
						_cardsSetRenderer[i].scaleX = .25;
						_cardsSetRenderer[i].scaleY = .25;

						glowFilter.blurX = 2;
						glowFilter.blurY = 2;
						glowFilter.alpha = .36;
						break;
					default:
						break;
				}
			}
		}
	}
}
